﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using NUnit.Framework;
using Streaming_Service.Enum;
using Streaming_Service.SQL_Ting;
using Streaming_Service.User;

namespace Streaming_Service.Test {
    [TestFixture]
    public class TestUser {
        private RentIt11 client;

        private string name;
        private string email;
        private string password;
        private DateTime dob;
        
        [SetUp]
        public void SetUp() {
            var TLDs = new[] {"dk", "com", "se", "no", "co.uk", "de", "sg"};

            name = DBFunc.RandStr((uint)DBFunc.Rand(5,10));
            email = (DBFunc.RandStr((uint)DBFunc.Rand(5,10)) + "@" + DBFunc.RandStr((uint)DBFunc.Rand(5,10)) + "." + TLDs[DBFunc.Rand(0, TLDs.Length - 1)]).ToLower();
            password = DBFunc.RandStr((uint)DBFunc.Rand(10,20));
            dob = new DateTime(DBFunc.Rand(1970, 1990), DBFunc.Rand(1, 12), DBFunc.Rand(1, 28));

            client = new RentIt11();

            Assert.That(!string.IsNullOrEmpty(name) && UserRegex.ValidName(name), "Name: " + name);
            Assert.That(!string.IsNullOrEmpty(email) && UserRegex.ValidEmail(email), "Email: " + email);
            Assert.That(!string.IsNullOrEmpty(password) && UserRegex.ValidPassword(password), "Password: " + password);
        }

        [Test]
        public void Creation() {
            var r = client.CreateAccount("", password, email, dob);
            Assert.That(r == UserReturnCode.InvalidName);

            r = client.CreateAccount(null, password, email, dob);
            Assert.That(r == UserReturnCode.InvalidName);

            r = client.CreateAccount(name, "", email, dob);
            Assert.That(r == UserReturnCode.InvalidPassword); 
            
            r = client.CreateAccount(name, null, email, dob);
            Assert.That(r == UserReturnCode.InvalidPassword);

            r = client.CreateAccount(name, password, "@.com", dob);
            Assert.That(r == UserReturnCode.InvalidEmail);

            r = client.CreateAccount(name, password, null, dob);
            Assert.That(r == UserReturnCode.InvalidEmail);

            r = client.CreateAccount(name, password, email, DateTime.Now);
            Assert.That(r == UserReturnCode.InvalidBirthday);

            r = client.CreateAccount(name, password, email, dob);
            Assert.That(r == UserReturnCode.Success);

            r = client.CreateAccount(name, password, email, dob);
            Assert.That(r == UserReturnCode.EmailInUse);

            var userInfo = client.GetUserInfoByEmail(email);

            var activationCode = client.GetActivationCode(userInfo.Id);

            client.ActivateAccount(userInfo.Id, activationCode);

            var session = client.Login(email, password);

            Assert.That(client.DeleteAccount(session, password) == UserReturnCode.Success);
        }

        [Test]
        public void Activation() {
            Assert.That(!client.ActivateAccount(0, "ABCDE"));
            Assert.That(!client.ActivateAccount(0, null));
            Assert.That(!client.ActivateAccount(-1, "ABCDE"));
            Assert.That(!client.ActivateAccount(-1, null));

            var r = client.CreateAccount(name, password, email, dob);
            Assert.That(r == UserReturnCode.Success);

            Assert.That(client.Login(email, password) == null);

            var userInfo = client.GetUserInfoByEmail(email);

            Assert.That(!client.IsAccountActivated(userInfo.Id));

            var activationCode = client.GetActivationCode(userInfo.Id);
            
            Assert.That(!client.ActivateAccount(userInfo.Id, null));
            Assert.That(!client.ActivateAccount(userInfo.Id, ""));
            Assert.That(!client.ActivateAccount(userInfo.Id, "A" + activationCode));
            Assert.That(!client.ActivateAccount(userInfo.Id, activationCode + "z"));
            Assert.That(!client.ActivateAccount(userInfo.Id, "A" + activationCode + "z"));
            Assert.That(client.ActivateAccount(userInfo.Id, activationCode));
            Assert.That(!client.ActivateAccount(userInfo.Id, activationCode));
            Assert.That(client.IsAccountActivated(userInfo.Id));

            var session = client.Login(email, password);
            Assert.That(client.DeleteAccount(session, password) == UserReturnCode.Success);
        }

        [Test]
        public void Authorization() {
            Assert.That(client.Login(null, null) == null);
            Assert.That(client.Login("", null) == null);
            Assert.That(client.Login(null, "") == null);
            Assert.That(client.Login("", "") == null);
            Assert.That(client.Login("test@test.com", null) == null);
            Assert.That(client.Login(null, "TESTpassword123") == null);
            Assert.That(client.Login("test@test.com", DBFunc.RandStr(30) + "µ") == null);

            var session = this.CreateTestAccount();
            Assert.That(session.Name == name);
            Assert.That(session.Birthday.Equals(dob));
            Assert.That(session.Email == email);
            Assert.That(!string.IsNullOrEmpty(session.Token));

            var prevUserId = session.UserId;
            client.Logout(session);
            Assert.That(client.DeleteAccount(session, password) == UserReturnCode.InvalidSession);

            session = client.Login(email, password);
            Assert.That(session != null && session.UserId == prevUserId);
            Assert.That(client.DeleteAccount(session, password) == UserReturnCode.Success);
        }

        [Test]
        public void Deletion() {
            Assert.That(client.DeleteAccount(null, null) == UserReturnCode.InvalidSession);
            Assert.That(client.DeleteAccount(new UserSession(), null) == UserReturnCode.InvalidSession);
            Assert.That(client.DeleteAccount(null, DBFunc.RandStr(20)) == UserReturnCode.InvalidSession);
            Assert.That(client.DeleteAccount(new UserSession(), DBFunc.RandStr(20)) == UserReturnCode.InvalidSession);

            var session = this.CreateTestAccount();

            Assert.That(client.DeleteAccount(session, null) == UserReturnCode.InvalidPassword);
            Assert.That(client.DeleteAccount(session, DBFunc.RandStr((uint)DBFunc.Rand(10, 20))) == UserReturnCode.InvalidPassword);
            Assert.That(client.DeleteAccount(session, "") == UserReturnCode.InvalidPassword);
            Assert.That(client.DeleteAccount(session, password) == UserReturnCode.Success);
        }

        [Test]
        public void UpdateUserInfo() {
            var session = this.CreateTestAccount();

            Assert.That(client.UpdateAccount(new UserSession(), null, null, null) == UserReturnCode.InvalidSession);
            Assert.That(client.UpdateAccount(session, null, null, null) == UserReturnCode.NothingToUpdate);
            Assert.That(client.UpdateAccount(session, "NEWpassWORD!", "", null) == UserReturnCode.Success);
            var newEmail = "newemail" + Environment.TickCount + "@host" + Environment.TickCount + ".com";
            Assert.That(client.UpdateAccount(session, "", newEmail, null) == UserReturnCode.Success);
            Assert.That(client.UpdateAccount(session, null, null, dob.AddDays(2)) == UserReturnCode.Success);

            Assert.That(client.UpdateAccount(session, null, newEmail, null) == UserReturnCode.EmailInUse);
            Assert.That(client.UpdateAccount(session, "na", null, null) == UserReturnCode.InvalidPassword);
            Assert.That(client.UpdateAccount(session, null, "@.com", null) == UserReturnCode.InvalidEmail);
            Assert.That(client.UpdateAccount(session, null, null, DateTime.Now) == UserReturnCode.InvalidBirthday);

            var userInfo = client.GetUserInfo(session.UserId);
            Assert.That(userInfo.Email == newEmail);

            Assert.That(client.DeleteAccount(session, "NEWpassWORD!") == UserReturnCode.Success);
        }

        [Test]
        public void OnlineUsers() {
            var session = this.CreateTestAccount();

            var allUsers = client.ListUsers();
            Assert.That(allUsers.Any(ui => ui.Id == session.UserId));

            var onlineUsers = client.ListOnlineUsers(600);
            Assert.That(onlineUsers.Any(ui => ui.Id == session.UserId));

            Assert.That(client.DeleteAccount(session, password) == UserReturnCode.Success);
        }

        [Test]
        public void AdminUserStuff() {
            var session = this.CreateTestAccount();
            var admin = GetAdminSession();

            Assert.That(client.AdminUpdateAccount(new UserSession(), -1, null, null, null, XBool.Ignore) == UserReturnCode.AdminRequired);
            Assert.That(client.AdminUpdateAccount(admin, -1, null, null, null, XBool.Ignore) == UserReturnCode.InvalidUserSpecified);
            Assert.That(client.AdminUpdateAccount(admin, session.UserId, null, null, null, XBool.Ignore) == UserReturnCode.NothingToUpdate);
            Assert.That(client.AdminUpdateAccount(admin, session.UserId, "NEWpassWORD!", "", null, XBool.False) == UserReturnCode.Success);
            Assert.That(client.AdminUpdateAccount(admin, session.UserId, "", "newemail" + Environment.TickCount + "@host" + Environment.TickCount + ".com", null, XBool.Ignore) == UserReturnCode.Success);
            Assert.That(client.AdminUpdateAccount(admin, session.UserId, null, null, dob.AddDays(2), XBool.False) == UserReturnCode.Success);
            Assert.That(client.AdminUpdateAccount(admin, session.UserId, null, null,null, XBool.True) == UserReturnCode.Success);

            Assert.That(client.AdminUpdateAccount(admin, session.UserId, null, null, null, XBool.True) == UserReturnCode.Success);

            Assert.That(client.AdminDeleteAccount(new UserSession(), -1) == UserReturnCode.AdminRequired);
            Assert.That(client.AdminDeleteAccount(admin, -1) == UserReturnCode.InvalidUserSpecified);
            Assert.That(client.AdminDeleteAccount(admin, session.UserId) == UserReturnCode.Success);
        }

        private UserSession CreateTestAccount() {
            var r = client.CreateAccount(name, password, email, dob);
            Assert.That(r == UserReturnCode.Success);
            Assert.That(client.Login(email, password) == null);

            var userInfo = client.GetUserInfoByEmail(email);
            var activationCode = client.GetActivationCode(userInfo.Id);
            Assert.That(client.ActivateAccount(userInfo.Id, activationCode));

            var session = client.Login(email, password);
            Assert.That(session != null && session.UserId > 0);

            return session;
        }

        public static UserSession GetAdminSession() {
            var client = new RentIt11();
            var asession = client.Login("ahal@itu.dk", "kjeldsen");
            Assert.That(asession.IsAdmin);
            return asession;
        }
    }
}